// const baseServer="http://127.0.0.1:4321";
import regeneratorRuntime from "regenerator-runtime";

import {util} from "utilities";
function initNaive(opt) {
    const baseServer = opt.baseServerApi;
    let utils = util({uploadApi: opt.uploadApi});
    let post = utils.post;
    let get = utils.get;
    let putFile = utils.putFile;
    let putFile2 = utils.putFile2;

    ServerAgent = {
        invoke: async (api, data) =>{
            let context;
            try {
                context = stack.get();
            } catch (e){
                console.log(e)
            }
            return await interactCallServer("logic", api, data,context)
        },
        putFile: async (data, type, cb) => {
            return cb(await putFile2(data, type))
        },
        get: async (api, data, cb) => cb(await get(api, data)),
    };
    getAgent = function (naive) {
        let context;
        try {
            context = stack.get();
        } catch (e){
            console.log(e)
        }
        return {
            invoke: async (api, data) => await interactCallServer(`naive/${naive}`, `invoke/${api}`, data,context),
        }
    };

    async function interactCallServer(type, api, data,context) {
        let response = await post(`${baseServer}/${type}/${api}`, data);
        return await interactionTypes[response.verb](response.next, response.args,context);
    }


    let hibernatingPromise={};
    let interactionTypes = {
        "wsconnect": async (next, naiveName,context) => {
            let targetNaive = await getNaive(naiveName);
            return await interactCallServer("interact", next, targetNaive.address,context);
        },
        "redirect": async (next, pck,context) => {
            let {url} = pck;
            console.log(`是否当前页面已经关闭`);
            console.log(context.isFinish);
            if (context.isFinish){
                context = stack.get();
            }
            context.open(url, pck);
            return await interactCallServer("interact", next, {},context);
        },
        "popup": async (next, pck,context) => {
            let {url} = pck;
            context.popup(url, pck);
            return await interactCallServer("interact", next, {},context);
        },
        "retrieve": async (next, list,context) => {
            let result = {};
            for (let key of list)
                result[key] = sp.get(key);
            return await interactCallServer("interact", next, result,context);
        },
        "info": async (next, result,context) => {
            alert(result);
            return await interactCallServer("interact", next, {},context);
            // return result;
        },
        "finish": (next, result,context) => result,
        "store": async (next, what,context) => {
            await sp.put(what);
            return await interactCallServer("interact", next, {success: true},context);
        },
        "input": async (next, pck,context) => {
            let{url} = pck;
            return new Promise(async (res, rej) => {
                let newWindow = await context.input(url, {
                        next: async (result) => {
                            post(`${baseServer}/interact/${next}`, result).then(async response=>{
                                console.log("input err","post");
                                res(await interactionTypes[response.verb](response.next, response.args,context));
                                console.log("input err ok");
                                newWindow.finish();
                            });
                        },
                        arguments: pck
                    }
                );
            });
        },
        "hibernate": (next, pck, context)=>{
            return new Promise((res, rej)=>{
                hibernatingPromise[pck.id] = {res,rej};
            }).then(async ()=>{
                delete hibernatingPromise[pck.id];
                return await interactCallServer("interact",next,{},context)
            });
        }
    };


    naives = {};
    let getNaive = (naiveName) => naives[naiveName].ready.then(() => naives[naiveName].naive);
    let genNaive = (naiveName) => {
        let uuid = "invalid";
        let cb = {};
        console.log(`generating naive:${naiveName}, connecting websocket...`);
        let connectionHandler;
        function setIO(){
            socket = io(baseServer);
            socket.on("id", (id) => {
                console.log(`socket进入id`);
                console.log(`naive ${naiveName} ready, id:${id}`);
                uuid = id;
                sp.put({uuid:uuid});
                naive.address = uuid;
                if (connectionHandler) connectionHandler();
            });
            socket.on("method", (data) => {
                console.log(`socket进入method`);
                console.log(`naive ${naiveName} being invoked: ${data.method}: ${data.args}`);
                let {id, method, args} = data;
                if (cb[method])
                    cb[method](id, args);
            });
            socket.on("disconnect", ()=>{
                console.log(`${uuid} destroyed`);
                let lastWSid=uuid;
                connectionHandler=async ()=>{
                    console.log("POST uuid to server");
                    await post(`${baseServer}/carryWS/`,{
                        lastWSid,
                        newWSid:uuid,
                    });
                }
            });
            return socket;
        }
        let ready = new Promise((res) => {
            connectionHandler=res;
            setIO()
        });
        let ondisconnectHandler=()=>{};
        let naive = {
            method: (name, fn) => {
                ready.then(() => {
                    cb[name] = async (id, args) => {
                        let result = await fn({}, args);
                        await post(`${baseServer}/verb/${id}/`, {verb: 'finish', args: result});
                    };
                });
            },
            ondisconnect(fn){
                ondisconnectHandler=fn;
            }
        };
        naives[naiveName] = {ready, naive};
        return naive;
    };
    return {genNaive,hibernatingPromise};
}

export {initNaive};